package com.sduept.nwld.dataview.controller.core;

import com.alibaba.fastjson.JSONObject;
import com.sduept.cim.model.core.Substation;
import com.sduept.cim.model.extend.LineSegment;
import com.sduept.cim.model.generation.GeneratingUnit;
import com.sduept.cim.model.generation.HydroGeneratingUnit;
import com.sduept.cim.model.generation.ThermalGeneratingUnit;
import com.sduept.cim.model.protection.ProtectionEquipment;
import com.sduept.cim.model.wires.*;
import com.sduept.bigdata.web.jsf.controller.AbstractController;
import com.sduept.bigdata.weather.map.MapDataCache;
import com.sduept.nwld.dataserver.manager.cim.CimManager;
import com.sduept.nwld.dataserver.util.LibTreeNode;
import com.sduept.utils.PingYinUtil;
import org.apache.commons.lang3.StringUtils;
import org.primefaces.event.NodeExpandEvent;
import org.primefaces.event.NodeSelectEvent;
import org.primefaces.event.SelectEvent;
import org.primefaces.model.DefaultTreeNode;
import org.primefaces.model.TreeNode;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import javax.faces.application.FacesMessage;
import javax.inject.Named;
import javax.faces.view.ViewScoped;
import javax.faces.context.FacesContext;
import java.util.*;
import java.util.Map.Entry;

/**
 * 设备选择器
 * 默认显示500kv及以上电压等级
 * 使用方法： 
 * 可选参数：
 * rootTypes:此参数选择显示根节点：变电站，直流线路，交流线路。若为空，选择所有类型。
 * 例如："ACLineSegment,Substation"
 * 
 * 
 * selectedTypes：此参数用于选择  "变电站"根节点的  子设备类型。若为空，则展示所有的类型。参数可选范围在stationTypeMap中。
 * 例如："ACLineSegment,PowerTransformer"
 * 
 * stationId：此参数用于选择 变电站。若有值，则会展示：变电站-电压等级-此变电站-子设备
 * 
 * chooseStation:默认点击"某变电站"时，显示确定按钮。若此参数为false，则点击变电站时，不显示确定按钮。
 *
 */
@Named
@ViewScoped
public class EquipmentSingleSelectorLayerController extends AbstractController {

	/**
	 * 
	 */
	private static final long serialVersionUID = 6250546447223200062L;
	@Autowired
	private CimManager cimMan;
	@Autowired
	private MapDataCache cimChe;

	private TreeNode root;

	private TreeNode selectedNode;

	private TreeNode[] selectedNodes;

	public static final String TREE_TYPE_Equipment = "Equipment";
	public static final String TREE_TYPE_Dir = "1";

	/**
	 * 根节点类型筛选列表
	 * 若为空，表示展示所有类型。可选选项在rootTypeMap中。
	 */
	private List<String> rootTypes = new ArrayList<>();

	/**
	 * 根节点-变电站的子类型筛选列表。
	 * 若为空，表示全部展示。可选选项在
	 */
	private List<String> stationTypes = new ArrayList<>();
	/**
	 * 根节点-变电站，被选中时，是否可以点击确定按钮
	 */
	private boolean chooseStation = true;
	/**
	 * 当此参数被赋值时，只展示 ：
	 * 根节点--变电站--此变电站--此变电站子节点
	 */
	private String stationId = null; 


	/**
	 * 根节点类型
	 */
	private LinkedHashMap<String, String> rootTypeMap = new LinkedHashMap<String,String>(){
		private static final long serialVersionUID = 830850083718751819L;
		{
			put(Substation.class.getSimpleName(), "变电站");
			put(ACLineSegment.class.getSimpleName(), "交流线路");
			put(DcLinesegment.class.getSimpleName(), "直流线路");
		}
	};
	//根节点--变电站的子类型
	private Map<String, String> stationTypeMap = new LinkedHashMap<String, String>() {
		private static final long serialVersionUID = 830850083718751819L;
		{
			put(ACLineSegment.class.getSimpleName(), "交流线路");
			put(DcLinesegment.class.getSimpleName(), "直流线路");
			put(BusbarSection.class.getSimpleName(), "母线");
			put(PowerTransformer.class.getSimpleName(), "变压器");
			put(GeneratingUnit.class.getSimpleName(), "发电机");
			put(ProtectionEquipment.class.getSimpleName(), "保护设备");
			put(Breaker.class.getSimpleName(), "断路器");
			put("", "其它");
		}
	};

	private String filter;
	private Map<String, TreeNode> lineFilters = new HashMap<>();
	private Map<String, TreeNode> StationFilters = new HashMap<>();
	private Map<String, String> filterResults = new HashMap<>();

	private Integer chooseVoltage = 500;
	private String selectedEquipmentJson = null;

	@PostConstruct
	public void init() {
		try {
			// 显示的类型（使用逗号分隔的实体类的名字）
			String rootType = getParameter("rootTypes");
			if (StringUtils.isNotEmpty(rootType)) {
				rootTypes = Arrays.asList(rootType.split(","));
				Iterator<Entry<String, String>> it = rootTypeMap.entrySet().iterator();  
				while(it.hasNext()){  
					Entry<String, String> entry = it.next();  
					if(!rootTypes.contains(entry.getKey())){
						it.remove();
					}
				}  
			}
			String stationType = getParameter("selectedTypes");
			if (StringUtils.isNotEmpty(stationType)) {
				stationTypes = Arrays.asList(stationType.split(","));
				Iterator<Entry<String, String>> it = stationTypeMap.entrySet().iterator();  
				while(it.hasNext()){  
					Entry<String, String> entry = it.next();  
					if(!stationTypes.contains(entry.getKey())){
						it.remove();
					}
				}  
			}
			stationId = getParameter("stationId");
			if (StringUtils.isNotEmpty(stationId)) {
				//当指定stationId时，只展示“变电站”节点+“电压等级”+本stationId的变电站
				rootTypeMap.clear();
				rootTypeMap.put(Substation.class.getSimpleName(), "变电站");
			}
			String cs = getParameter("chooseStation");
			if (StringUtils.isNotEmpty(cs)) {
				chooseStation = Boolean.parseBoolean(cs);
			}
			initTree();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void initTree() {
		root = new LibTreeNode();
		Integer[] vs = getVoltageRange(chooseVoltage);
		boolean isFirst = true ;
		for(Map.Entry<String, String> en:rootTypeMap.entrySet()){
			String className = en.getKey();
			TreeNode snode = new DefaultTreeNode(TREE_TYPE_Dir, en.getValue(), root);

			if(Substation.class.getSimpleName().equals(className)){
				List<Substation> stationObjects = new ArrayList<>();
				if(StringUtils.isEmpty(stationId)){
					stationObjects = cimChe.getStationsByVoltage(vs[0], vs[1]);
				}else{
					Substation s = cimChe.getStationid_map().get(stationId);
					if(s != null){
						stationObjects.add(s);
					}else{
						FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, null, "未找到所选变电站！"));
					}
				}

				genStationTreeNode(stationObjects, snode);
			}else if(ACLineSegment.class.getSimpleName().equals(className)){

				HashMap<String, ACLineSegment> lineObjects = cimChe.getAcLineIdMapByVoltage(vs[0], vs[1]);
				genLineTreeNode(lineObjects.values(), snode);
			}else if(DcLinesegment.class.getSimpleName().equals(className)){

				HashMap<String, DcLinesegment> lineObjects = cimChe.getDcLineIdMapByVoltage(vs[0], vs[1]);
				genLineTreeNode(lineObjects.values(), snode);
			}
			if(isFirst){
				snode.setExpanded(true);
				isFirst = false;
			}
		}
	}

	private Integer[] getVoltageRange(Integer chooseVoltage) {
		Integer[] v = new Integer[]{null,null};
		if (chooseVoltage-220 == 0) {
			v[0] = 200;
			v[1] = 500;
		} else if (chooseVoltage - 500 == 0) {
			v[0] = 500;
		} else if (chooseVoltage - 800 == 0) {
			v[0] = 800;
		}
		return v;
	}

	private void addToFilter(String name, TreeNode node, Map<String, TreeNode> filters) {
		String py = PingYinUtil.getPingYinHeader(name);
		String key = py;
		int i = 1;// 为了消除 山花甲线 山河甲线 的拼音简写相同的bug
		while (StringUtils.isNotEmpty(filterResults.get(key))) {
			key += i;
			i++;
		}
		filters.put(name, node);
		filters.put(key, node);
		filterResults.put(key, name);
		filterResults.put(name, name);
	}

	private void genLineTreeNode(Collection<? extends LineSegment> roots, TreeNode parent) {
		TreeMap<Float,DefaultTreeNode> voltages = new TreeMap<>();
		for (LineSegment line : roots) {
			voltages.put(line.getStandVoltagelevel(), null);
		}

		for( Map.Entry<Float, DefaultTreeNode> en: voltages.entrySet()){
			DefaultTreeNode vnode = new DefaultTreeNode(TREE_TYPE_Dir, en.getKey().intValue() + "kV", parent);
			voltages.put(en.getKey(), vnode);
			vnode.setExpanded(true);
		}

		for (LineSegment line : roots) {
			for (Entry<Float, DefaultTreeNode> en : voltages.entrySet()) {
				if (en.getKey() - line.getStandVoltagelevel() == 0) {
					DefaultTreeNode subNode = new DefaultTreeNode(TREE_TYPE_Equipment, line, en.getValue());
					if(line instanceof DcLinesegment) {
						addToFilter(StringUtils.isNotEmpty(line.getAliasName())?line.getAliasName():line.getName(), subNode, lineFilters);
					}else {
						addToFilter(line.getName(), subNode, lineFilters);
					}
					break;
				}
			}
		}
	}

	private void genStationTreeNode(List<Substation> roots, TreeNode parent) {
		for (int i = 0; i < roots.size(); i++) {
			Substation sub = roots.get(i);
			LibTreeNode subNode = new LibTreeNode(Substation.class.getSimpleName(), sub, parent);
			addToFilter(sub.getName(), subNode, StationFilters);
			//			if (i == 0) {
			//				subNode.setExpanded(true);
			//			}
			for (Map.Entry<String, String> en : stationTypeMap.entrySet()) {
				new LibTreeNode(TREE_TYPE_Dir, new DirNode(sub.getId(), en.getValue(), en.getKey()), subNode);
			}
		}
	}

	public class DirNode {
		public String id;
		public String name;
		public String className;

		@Override
		public String toString() {
			return name;
		}

		public DirNode(String id, String name, String className) {
			this.id = id;
			this.name = name;
			this.className = className;
		}
	}

	public void changeVoltage(){
		filterResults.clear();
		lineFilters.clear();
		StationFilters.clear();
		initTree();
	}
	private void expand(TreeNode currentNode) {
		//动态加载变电站的子目录。线路的子目录是加载好的。
		if (currentNode.getData() instanceof DirNode) {
			DirNode currentObj = (DirNode) currentNode.getData();
			if (ACLineSegment.class.getSimpleName().equals(currentObj.className)) {
				List<ACLineSegment> beans = cimMan.getAcLineSegmentsBySubstation(currentObj.id);
				for (ACLineSegment bean : beans) {
					DefaultTreeNode subNode = new DefaultTreeNode(TREE_TYPE_Equipment, bean, currentNode);
					addToFilter(bean.getName(), subNode, StationFilters);
				}
			}else if (DcLinesegment.class.getSimpleName().equals(currentObj.className)) {
				List<DcLinesegment> beans = cimMan.getDcLineSegmentsBySubstation(currentObj.id);
				for (DcLinesegment bean : beans) {
					DefaultTreeNode subNode = new DefaultTreeNode(TREE_TYPE_Equipment, bean, currentNode);
					addToFilter(StringUtils.isNotEmpty(bean.getAliasName())?bean.getAliasName():bean.getName(), subNode, StationFilters);
				}
			} else if (Breaker.class.getSimpleName().equals(currentObj.className)) {
				List<Breaker> beans = cimMan.getBreakersByStationId(currentObj.id);
				for (Breaker bean : beans) {
					DefaultTreeNode subNode = new DefaultTreeNode(TREE_TYPE_Equipment, bean, currentNode);
					addToFilter(bean.getName(), subNode, StationFilters);
				}
			} else if (BusbarSection.class.getSimpleName().equals(currentObj.className)) {
				List<BusbarSection> beans = cimMan.getBusbarSectionsByStationId(currentObj.id);
				for (BusbarSection bean : beans) {
					DefaultTreeNode subNode = new DefaultTreeNode(TREE_TYPE_Equipment, bean, currentNode);
					addToFilter(bean.getName(), subNode, StationFilters);
				}
			} else if (PowerTransformer.class.getSimpleName().equals(currentObj.className)) {
				List<PowerTransformer> beans = cimMan.getPowerTransformersByStationId(currentObj.id);
				for (PowerTransformer bean : beans) {
					TreeNode node = new LibTreeNode(TREE_TYPE_Equipment, bean, currentNode);
					addToFilter(bean.getName(), node, StationFilters);
					List<TransformerWinding> beans1 = cimMan.getTransformerWindingsBypowerTransformerRdfId(bean.getRdfId());
					for (TransformerWinding bean1 : beans1) {
						DefaultTreeNode subNode = new DefaultTreeNode(TREE_TYPE_Equipment, bean1, node);
						addToFilter(bean1.getName(), subNode, StationFilters);
					}
				}
			} else if (ProtectionEquipment.class.getSimpleName().equals(currentObj.className)) {
				List<ProtectionEquipment> beans = cimMan.getProtectionEquipmentsByStationId(currentObj.id);
				for (ProtectionEquipment bean : beans) {
					DefaultTreeNode subNode = new DefaultTreeNode(TREE_TYPE_Equipment, bean, currentNode);
					addToFilter(bean.getName(), subNode, StationFilters);
				}
			} else if (GeneratingUnit.class.getSimpleName().equals(currentObj.className)) {
				List<GeneratingUnit> gu = cimMan.getGeneratingUnitsByStationId(currentObj.id);
				for (GeneratingUnit generatingUnit : gu) {
					DefaultTreeNode subNode = new DefaultTreeNode(TREE_TYPE_Equipment, generatingUnit,
							currentNode);
					addToFilter(generatingUnit.getName(), subNode, StationFilters);
				}
				List<HydroGeneratingUnit> hu = cimMan.getHydroGeneratingUnitsByStationId(currentObj.id);
				for (HydroGeneratingUnit hydroGeneratingUnit : hu) {
					DefaultTreeNode subNode = new DefaultTreeNode(TREE_TYPE_Equipment, hydroGeneratingUnit,
							currentNode);
					addToFilter(hydroGeneratingUnit.getName(), subNode, StationFilters);
				}
				List<ThermalGeneratingUnit> tu = cimMan.getThermalGeneratingUnitsByStationId(currentObj.id);
				for (ThermalGeneratingUnit thermalGeneratingUnit : tu) {
					LibTreeNode subNode = new LibTreeNode(TREE_TYPE_Equipment, thermalGeneratingUnit,
							currentNode);
					addToFilter(thermalGeneratingUnit.getName(), subNode, StationFilters);
				}
			} else {
				List<Compensator> beans = cimMan.getCompensatorsByStationId(currentObj.id);
				for (Compensator bean : beans) {
					DefaultTreeNode subNode = new DefaultTreeNode(TREE_TYPE_Equipment, bean, currentNode);
					addToFilter(bean.getName(), subNode, StationFilters);
				}
			}
		}
	}

	public void onNodeExpand(NodeExpandEvent event) {
		TreeNode node = event.getTreeNode();
		expand(node);
	}

	public void onNodeSelect(NodeSelectEvent event) {
		selectedNode = event.getTreeNode();
	}

	public void selectSingleDialog() {
		// 单选
		if (selectedNode != null) {
			String className = "";
			String classPath = "";
			String data = "";
			if((TREE_TYPE_Equipment.equals(selectedNode.getType()))
					|| (chooseStation && Substation.class.getSimpleName().equals(selectedNode.getType()))) {
				Object o = selectedNode.getData();
				if(o instanceof Substation) {
					Substation p = (Substation) o;
					className = Substation.class.getSimpleName();
					classPath = Substation.class.getName();
					data = JSONObject.toJSONString(p);
				}else if(o instanceof ACLineSegment) {
					ACLineSegment p = (ACLineSegment) o;
					classPath = ACLineSegment.class.getName();
					className = ACLineSegment.class.getSimpleName();
					data = JSONObject.toJSONString(p);
				}else if(o instanceof DcLinesegment) {
					DcLinesegment p = (DcLinesegment) o;
					classPath = DcLinesegment.class.getName();
					className = DcLinesegment.class.getSimpleName();
					data = JSONObject.toJSONString(p);
				} else if (o instanceof Breaker) {
					classPath = Breaker.class.getName();
					Breaker p = (Breaker) o;
					className = Breaker.class.getSimpleName();
					data = JSONObject.toJSONString(p);
				} else if (o instanceof BusbarSection) {
					BusbarSection p = (BusbarSection) o;
					classPath = BusbarSection.class.getName();
					className = BusbarSection.class.getSimpleName();
					data = JSONObject.toJSONString(p);
				} else if (o instanceof PowerTransformer) {
					PowerTransformer p = (PowerTransformer) o;
					classPath = PowerTransformer.class.getName();
					className = PowerTransformer.class.getSimpleName();
					data = JSONObject.toJSONString(p);
				} else if (o instanceof ProtectionEquipment) {
					ProtectionEquipment p = (ProtectionEquipment) o;
					classPath = ProtectionEquipment.class.getName();
					className = ProtectionEquipment.class.getSimpleName();
					data = JSONObject.toJSONString(p);
				} else if (o instanceof GeneratingUnit) {
					GeneratingUnit p = (GeneratingUnit) o;
					classPath = GeneratingUnit.class.getName();
					className = GeneratingUnit.class.getSimpleName();
					data = JSONObject.toJSONString(p);
				}
			}
			JSONObject r = new JSONObject();
			r.put("className", className);
			r.put("classPath", classPath);
			r.put("data", data);
			selectedEquipmentJson = r.toJSONString();
		} else {
			addErrorMessage("请选择设备");
		}
		
	}

	public List<String> completeEquipments(String query) {
		List<String> results = new ArrayList<String>();
		for (String s1 : filterResults.keySet()) {
			if (s1.startsWith(query)) {
				results.add(filterResults.get(s1));
			}
		}
		return results;
	}

	public void autoCompleteEquipment(SelectEvent event) {
		Object item = event.getObject();
		boolean isSelected = true;
		if (null != item) {
			root.getChildren().clear();
			TreeNode linef = lineFilters.get(item.toString());
			if (linef != null) {
				TreeNode ln = expandParentNode(linef);
				root.getChildren().add(ln);
				isSelected = !isSelected;
				return;
			}

			TreeNode stationf = StationFilters.get(item.toString());
			if (stationf != null) {
				TreeNode sn = expandParentNode(stationf);
				root.getChildren().add(sn);
				if (isSelected) {
					selectedNode = stationf;
				}
			}
		}
	}

	private TreeNode expandParentNode(TreeNode node) {
		TreeNode pNode = node.getParent();
		if (pNode != null) {
			pNode.getChildren().clear();
			pNode.getChildren().add(node);
			if (pNode.getRowKey() == "root") {
				return node;
			}
			pNode.setExpanded(true);
			return expandParentNode(pNode);
		} else {
			return node;
		}
	}

	public void refresh() {
		filter = null;
		selectedNode = null;
		initTree();
	}

	public boolean showChooseBtn() {
		if (selectedNode != null){
			if(TREE_TYPE_Equipment.equals(selectedNode.getType())
					|| (chooseStation && Substation.class.getSimpleName().equals(selectedNode.getType()))) {
				return true;
			}
		}
		return false;
	}

	public TreeNode getRoot() {
		return root;
	}

	public void setRoot(TreeNode root) {
		this.root = root;
	}

	public TreeNode getSelectedNode() {
		return selectedNode;
	}

	public void setSelectedNode(TreeNode selectedNode) {
		this.selectedNode = selectedNode;
	}

	public TreeNode[] getSelectedNodes() {
		return selectedNodes;
	}

	public void setSelectedNodes(TreeNode[] selectedNodes) {
		this.selectedNodes = selectedNodes;
	}

	public String getFilter() {
		return filter;
	}

	public void setFilter(String filter) {
		this.filter = filter;
	}

	public String getTREE_TYPE_Equipment() {
		return TREE_TYPE_Equipment;
	}

	public Integer getChooseVoltage() {
		return chooseVoltage;
	}

	public void setChooseVoltage(Integer chooseVoltage) {
		this.chooseVoltage = chooseVoltage;
	}

	public String getStationId() {
		return stationId;
	}

	public void setStationId(String stationId) {
		this.stationId = stationId;
	}

	public String getSelectedEquipmentJson() {
		return selectedEquipmentJson;
	}

	public void setSelectedEquipmentJson(String selectedEquipmentJson) {
		this.selectedEquipmentJson = selectedEquipmentJson;
	}


}
